package com.hb.A_基础.B_高阶函数和lambda

/**
 * 在Kotlin中，函数类型的格式很简单
 * 比如：
 *  （Int）->Unit
 *  从中我们发现，Kotlin中的`函数类型声明`遵循以下几点：
 *      1. 通过->符号来组织参数类型和返回值类型，左边是参数类型，右边是返回值
 *      2. 必须用一个括号来包裹参数类型
 *      3. 返回值类型即Unit,也必须显示声明
 *  注意：如果是一个没有参数的函数类型，参数类型部分就用()来表示
 *  如：（）->Unit
 *  如果是多个参数的情况下，那么我们就需要用逗号来进行分隔。
 *  如：（Int,Long）->Long
 *
 *  此外，Kotlin还支持为声明的参数指定名字
 *  (errorCode:Int,errMsg:String) ->Unit
 *  如果errMsg在某种情况下可空：
 *  (errorCode:Int,errMsg:String?) ->Unit
 *
 *  如果函数类型的变量也是可选的话，我们还可以把整个函数类型编程可选的：
 *  ((errorCode:Int,errMsg:String?) ->Unit)?
 *
 *  高阶函数还支持返回另一个函数，所以还可以这么做：
 *      (Int) ->((Int)->Unit)
 *  这表示传入一个类型为Int的参数，然后返回另一个类型 (Int)->Unit的函数。
 *  简化他的表达式，我们可以把后半部分的括号省略：
 *  (Int) ->(Int)->Unit
 */
fun main() {
    val list = listOf<Country>(Country("EU", "EU", 100000), Country("DONG", "B", 100))
//    filterCountries(list, ::isBigEuropeanCountry).forEach(::println)
    println(::isBigEuropeanCountry)

    //::isBigEuropeanCountry表示的是函数的引用
    val bigEuropeanCountry = ::isBigEuropeanCountry
    println(bigEuropeanCountry(Country("EU", "EU", 100000)))

    filterCountries(list,::isBigEuropeanCountry).forEach(::println)




    /**
     * it：表示函数参数的参数：这里比如value
     */
    val a=get4 {
        input -> test(input)
    }
    println(a)





}


//增加了一个函数类型的参数test
fun filterCountries(countries:List<Country>,test:(Country)->Boolean):List<Country>{
    val res = mutableListOf<Country>()
    for (country in countries) {
        //直接调用test来进行筛选的
        if (test(country)){
           res.add(country)
       }
    }
    return  res
}
/**
 * 那么，下一个问题来了。我们如何才能把isBigEuropeanCountry方法传递给filterCountries呢？
 * 直接把isBigEuropeanCountry方法当做参数肯定不行，因为函数名并不是一个表达式，不具有类型信息
 * 它在带上括号、被执行后才存在值。可以看出我们需要的是一个单纯的方法引用表达式
 * 用它在filterCountries内部来调用参数。
 *
 */
fun isBigEuropeanCountry(country:Country):Boolean{
    return country.continent == "EU" && country.population >1000
}

fun get4(fn:(value: String) ->String):String=
    "2"

fun test(value:String):String{
    print(value)
  return  value
}

fun test2():String=
    " 12"

